import io from 'socket.io-client'
import Store from '../store/index';
const socket = io.connect('/'); // 连接3000 信令服务器

const CLIENT_RTC_EVENT = 'CLIENT_RTC_EVENT';
const SERVER_RTC_EVENT = 'SERVER_RTC_EVENT';

const CLIENT_USER_EVENT = 'CLIENT_USER_EVENT';
const SERVER_USER_EVENT = 'SERVER_USER_EVENT';

const CLIENT_USER_EVENT_LOGIN = 'CLIENT_USER_EVENT_LOGIN'; // 登录

const SERVER_USER_EVENT_UPDATE_USERS = 'SERVER_USER_EVENT_UPDATE_USERS';

const SIGNALING_OFFER = 'SIGNALING_OFFER';
const SIGNALING_ANSWER = 'SIGNALING_ANSWER';
const SIGNALING_CANDIDATE = 'SIGNALING_CANDIDATE';

let remoteRoom = ''; // 远端用户
let localRoom = ''; // 本地登录用户

function log(msg) {
    console.log(`[client] ${msg}`);
}

// socket.on('connect', function () {
//     log('ws connect.');
// });

// socket.on('connect_error', function () {
//     log('ws connect_error.');
// });

// socket.on('error', function (errorMessage) {
//     log('ws error, ' + errorMessage);
// });

// 监听更新
socket.on(SERVER_USER_EVENT, function (msg) {
    console.log(msg, 1231231)
    const type = msg.type;
    const payload = msg.payload;
    switch (type) {
        // 发现有人创房间了  房间列表需要更新
        case SERVER_USER_EVENT_UPDATE_USERS:
            updateUserList(payload);
            break;
    }
    log(`[${SERVER_USER_EVENT}] [${type}], ${JSON.stringify(msg)}`);
});
// 监听信令事件
socket.on(SERVER_RTC_EVENT, function (msg) {
    const { type } = msg;

    switch (type) {
        case SIGNALING_OFFER:
            handleReceiveOffer(msg);
            break;
        case SIGNALING_ANSWER:
            handleReceiveAnswer(msg);
            break;
        case SIGNALING_CANDIDATE:
            handleReceiveCandidate(msg);
            break;
    }
});
// 建立完连接之后执行的回调
async function handleReceiveOffer(msg) {
    log(`receive remote description from ${msg.payload.from}`);

    // 设置远端描述
    const remoteDescription = new RTCSessionDescription(msg.payload.sdp);
    remoteRoom = msg.payload.from;
    createPeerConnection();
    await pc.setRemoteDescription(remoteDescription); // TODO 错误处理

    // 本地音视频采集
    // const localVideo = document.getElementById('local-video');
    const mediaStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
    // localVideo.srcObject = mediaStream;
    mediaStream.getTracks().forEach(track => {
        pc.addTrack(track, mediaStream);
        // pc.addTransceiver(track, {streams: [mediaStream]}); // 这个也可以
    });
    // pc.addStream(mediaStream); // 目前这个也可以，不过接口后续会废弃

    const answer = await pc.createAnswer(); // TODO 错误处理
    await pc.setLocalDescription(answer);
    sendRTCEvent({
        type: SIGNALING_ANSWER,
        payload: {
            sdp: answer,
            from: localRoom,
            target: remoteRoom
        }
    });
}
// 设置answer =》 ice candidate answer 
async function handleReceiveAnswer(msg) {
    log(`receive remote answer from ${msg.payload.from}`);

    const remoteDescription = new RTCSessionDescription(msg.payload.sdp);
    remoteRoom = msg.payload.from;

    await pc.setRemoteDescription(remoteDescription); // TODO 错误处理
}

async function handleReceiveCandidate(msg) {
    log(`receive candidate from ${msg.payload.from}`);
    await pc.addIceCandidate(msg.payload.candidate); // TODO 错误处理
}

/**
 * 发送用户相关消息给服务器
 * @param {Object} msg 格式如 { type: 'xx', payload: {} }
 */
function sendUserEvent(msg) {
    socket.emit(CLIENT_USER_EVENT, JSON.stringify(msg));
}

/**
 * 发送RTC相关消息给服务器
 * @param {Object} msg 格式如{ type: 'xx', payload: {} }
 */
function sendRTCEvent(msg) {
    socket.emit(CLIENT_RTC_EVENT, JSON.stringify(msg));
}

let pc = null;

/**
 * 邀请用户加入视频聊天
 *  1、本地启动视频采集
 *  2、交换信令
 */
async function startVideoTalk(remoteRoom) {
    const localVideo = document.getElementById('local-video');
    const mediaStream = await navigator.mediaDevices.getUserMedia({
        video: true,
        audio: true
    });
    localVideo.srcObject = mediaStream;
    createPeerConnection(remoteRoom);
    mediaStream.getTracks().forEach(track => {
        pc.addTrack(track, mediaStream);
    });
}

function createPeerConnection(remoteRoom) {
    const iceConfig = {
        "iceServers": [
            { url: 'stun:stun.ekiga.net' },
            { url: 'turn:turnserver.com', username: 'user', credential: 'pass' }
        ]
    };

    pc = new RTCPeerConnection(iceConfig);

    pc.onnegotiationneeded = onnegotiationneeded;
    pc.onicecandidate = onicecandidate;
    pc.ontrack = remoteRoom ? ontrack : () => { };
    return pc;
}

async function onnegotiationneeded() {
    log(`onnegotiationneeded.`);

    const offer = await pc.createOffer();
    await pc.setLocalDescription(offer); // TODO 错误处理

    sendRTCEvent({
        type: SIGNALING_OFFER,
        payload: {
            from: localRoom,
            target: remoteRoom,
            sdp: pc.localDescription // TODO 直接用offer？
        }
    });
}
function onicecandidate(evt) {
    if (evt.candidate) {
        log(`onicecandidate.`);

        sendRTCEvent({
            type: SIGNALING_CANDIDATE,
            payload: {
                from: localRoom,
                target: remoteRoom,
                candidate: evt.candidate
            }
        });
    }
}


// 获取远端视频流
function ontrack(evt) {
    const remoteVideo = document.getElementById('remote-video');
    remoteVideo.srcObject = evt.streams[0];
}


// 点击用户列表
async function handleUserClick({ roomId }) {

    if (roomId === localRoom) {
        alert('不能跟自己进行视频会话');
        return;
    }
    remoteRoom = roomId;
    await startVideoTalk(remoteRoom);
}
/**
 * 更新用户列表
 * @param {Array} rooms 房间列表，比如 [{name: '小明', name: '小强'}]
 */
function updateUserList(rooms) {
    console.log(rooms, 123123123123)
    Store.commit('room/SET_ROOM_LIST', rooms)
}

/**
 * 用户登录
 * @param {String} loginName 用户名
 */
function createRoom({ roomId, roomName, userName, img }) {
    console.log(roomId, roomName, userName, img, 1231231)
    localRoom = roomId;
    sendUserEvent({
        type: CLIENT_USER_EVENT_LOGIN,
        payload: {
            roomId,
            roomName,
            userName,
            roomImg: img
        }
    });
}

export { createRoom, startVideoTalk, handleUserClick }